package com.hjlsoft.aftpclient;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.hjlsoft.aftp.common.StringUtil;
import com.hjlsoft.aftp.ins.AftpResultCode;
import com.hjlsoft.aftpclient.data.BodyParser;
import com.hjlsoft.aftpclient.data.DataInfo;

public abstract class AbstractAftpClient implements AftpClient {

	protected static final String SPACE = " ";
	
	protected static final String CRLF = "\r\n";
	
	protected static final String CHARSET = "utf-8";
	
	protected static final int BUF_SIZE = 1024 * 4;
	
	protected final Logger log = LoggerFactory.getLogger(getClass());
	
	private static final BodyParser<Void> voidParser = new BodyParser<Void>() {

		public Void parse(List<String> lines) {
			return null;
		}
		
	};
	
	private static final BodyParser<String> stringParser = new BodyParser<String>() {

		public String parse(List<String> lines) {
			if (lines == null || lines.isEmpty()) {
				return null;
			}
			return lines.get(0);
		}
		
	};
	
	private static final BodyParser<DataInfo> dataInfoParser = new BodyParser<DataInfo>() {

		public DataInfo parse(List<String> lines) {
			if (lines == null || lines.isEmpty()) {
				return null;
			}
			String line = lines.get(0);
			List<String> parts = StringUtil.splitTrim(line, "\\s+");
			DataInfo dataInfo = new DataInfo();
			dataInfo.setCreateTime(Long.parseLong(parts.get(0)));
			dataInfo.setUploadedSize(Long.parseLong(parts.get(1)));
			dataInfo.setTotalSize(Long.parseLong(parts.get(2)));
			return dataInfo;
		}
		
	};
	
	
	protected <T> AftpResult<T> execute(String ins, BodyParser<T> parser, Object... params) throws IOException {
		return execute(ins, null, parser, params);
	}
	
	protected abstract <T> AftpResult<T> execute(String ins, InputStream body, BodyParser<T> parser, Object... params) throws IOException;
	
	public AftpResult<Void> auth(String username, String password) throws IOException {
		return execute("auth", voidParser, username, password);
	}

	public AftpResult<Void> check(String token, String checkCode) throws IOException {
		return execute("check", voidParser, token, checkCode);
	}

	public AftpResult<Void> commit(String token, String commitTag) throws IOException {
		return execute("commit", voidParser, token, commitTag);
	}

	public AftpResult<String> createToken() throws IOException {
		return execute("create_token", stringParser);
	}

	public AftpResult<DataInfo> info(String token) throws IOException {
		return execute("info", dataInfoParser, token);
	}

	public AftpResult<Void> ping() throws IOException {
		return execute("ping", voidParser);
	}

	public AftpResult<Void> reset(String token) throws IOException {
		return execute("reset", voidParser, token);
	}

	public AftpResult<Void> upload(String token, long length, InputStream body) throws IOException {
		return execute("upload", body, voidParser, token, length);
	}

	public AftpResult<Void> uploadFile(String token, File file) throws IOException {
		AftpResult<DataInfo> dataInfoResult = info(token);
		long len = file.length();
		FileInputStream fis = new FileInputStream(file);
		
		if (dataInfoResult.getCode() == AftpResultCode.DATA_NOT_EXIST.getCode()) {
			// first create data
			return upload(token, len,fis);
		}
		
		if (dataInfoResult.getCode() == AftpResultCode.SUCCESS.getCode()) {
			// has exist
			DataInfo dataInfo = dataInfoResult.getData();
			log.debug("dataInfo:" + dataInfo);
			long pos = dataInfo.getUploadedSize();
			fis.skip(pos);
			return upload(token, len, fis);
		}
		
		AftpResult<Void> ret = new AftpResult<Void>();
		ret.setCode(dataInfoResult.getCode());
		ret.setMessage(dataInfoResult.getMessage());
		return ret;
	}
		
		

}
